package com.lhl.mq.mqServer.core;

import com.lhl.mq.common.MqException;


/**
 * 使用这个类用来sxian
 */

public class Router {

    //判断bindingKey是否合法
    //1、数字、字母、下划线
    //2、使用 . 将bindingKey分为多个独立的部分
    //3、特殊字符 #（匹配0个或多个独立的部分） *（匹配一个独立的部分）
    public boolean checkBindingKey(String bindingKey){
        int length = bindingKey.length();
        //如果长度为0的话，就相当于是 fanout 交换机
        if (length == 0){
            return true;
        }

        for (int i = 0; i < length; i++) {
            char str = bindingKey.charAt(i);
            if (str >= '0' && str <= '9'){
                continue;
            }

            if (str >= 'A' && str <= 'Z'){
                continue;
            }

            if (str >= 'a' && str <= 'z') {
                continue;
            }

            if (str == '*' || str == '#' || str == '_' || str == '.'){
                continue;
            }

            //还要判断 */# 是否是作为一个独立的部分
            String[] words = bindingKey.split("\\.");
            for (int j = 0; j < words.length; j++) {
                if (words[j].length() > 1 && (words[j].contains("#")) || (words[j].contains("*"))){
                    return false;
                }
            }
            return false;
        }
        return true;
    }


    //判断routingKey是否合法
    //1、数字、字母、下划线
    //2、使用 . 将routingKey划分为多个独立的部分
    public boolean checkRoutingKey(String routingKey){
        int length = routingKey.length();
        if (length == 0){
            //当交换机类型为 fanout 类型的时候，routingKey此时就用不上了
            return true;
        }

        for (int i = 0; i < length; i++) {

            char str = routingKey.charAt(i);
            if (str >= '0' && str <= '9'){
                continue;
            }
            if (str >= 'A' && str <= 'Z'){
                continue;
            }
            if (str >= 'a' && str <= 'z'){
                continue;
            }
            if (str == '.' || str == '_'){
                continue;
            }
            return false;
        }
        return true;
    }


    //用于判断该消息是否应该发给某个队列
    public boolean rout(ExchangeType type,Binding binding,Message message) throws MqException {
        //判断交换机的类型
        if (type == ExchangeType.FANOUT){
            //全部队列都要发送,直接返回true
            return true;
        }else if (type == ExchangeType.TOPIC){
            //将bindingKey与messageKey进行匹配
            //匹配成功则返回true，失败返回false
            return routeTopic(binding.getBindingKey(),message.getRoutingKey());
        }else {
            //如果是出现其他情况，直接则抛出异常
            throw new MqException("[Router] 交换机类型非法，exchangeType = " + type );
        }
    }

    public boolean routeTopic(String bindingKey,String routingKey){
        //将字符串划分为字符数组
        String[] bindingTokens = bindingKey.split("\\.");
        String[] routingTokens = routingKey.split("\\.");

        int bindingIndex = 0;
        int routingIndex = 0;

        //对里面的每一个元素进行比较
        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length){
            if (bindingTokens[bindingIndex].equals("#")){
                bindingIndex++;
                if (bindingIndex == bindingTokens.length){
                    return true;
                }
                //去routingTokens里面找是否有配对的字符
                //-1 不配对  routingKey合法的坐标则 配对
                routingIndex = findNextMatch(routingIndex,bindingTokens[bindingIndex],routingKey);
                if (routingIndex == -1){
                    return false;
                }

                bindingIndex++;
                routingIndex++;
            }else if(bindingTokens[bindingIndex].equals("*")){
                bindingIndex++;
                routingIndex++;
            }else {
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])){
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        if (bindingIndex == bindingTokens.length && routingIndex == routingTokens.length){
            return true;
        }
        return false;
    }

    private int findNextMatch(int routingIndex, String bindingToken, String routingKey) {
        String[] routingTokens = routingKey.split("\\.");

        for (int i = routingIndex; i < routingTokens.length; i++) {
            if (routingTokens[i].equals(bindingToken)){
                return i;
            }
        }
        return -1;

    }


}
